using Microsoft.EntityFrameworkCore;
using SheLife.Domain.Entities;
using SheLife.Domain.Interfaces.Repositories;
using SheLife.Infrastructure.Data;

namespace SheLife.Infrastructure.Repositories
{
    public class DietRecordRepository : Repository<DietRecord>, IDietRecordRepository
    {
        public DietRecordRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<DietRecord>> GetByUserIdAndDateAsync(Guid userId, DateTime date)
        {
            return await _dbSet
                .Where(d => d.UserId == userId && d.Date.Date == date.Date)
                .OrderBy(d => d.MealTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<DietRecord>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet
                .Where(d => d.UserId == userId && d.Date >= startDate && d.Date <= endDate)
                .OrderBy(d => d.Date)
                .ThenBy(d => d.MealTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<DietRecord>> GetByUserIdAndMealTypeAsync(Guid userId, string mealType)
        {
            return await _dbSet
                .Where(d => d.UserId == userId && d.MealType == mealType)
                .OrderByDescending(d => d.Date)
                .ThenBy(d => d.MealTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<DietRecord>> GetByUserIdAndFoodNameAsync(Guid userId, string foodName)
        {
            return await _dbSet
                .Where(d => d.UserId == userId && d.FoodName.Contains(foodName))
                .OrderByDescending(d => d.Date)
                .ThenBy(d => d.MealTime)
                .ToListAsync();
        }
    }

    public class DietNutrientRepository : Repository<DietNutrient>, IDietNutrientRepository
    {
        public DietNutrientRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<DietNutrient>> GetByDietRecordIdAsync(Guid dietRecordId)
        {
            return await _dbSet
                .Where(d => d.DietRecordId == dietRecordId)
                .ToListAsync();
        }

        public async Task<IEnumerable<DietNutrient>> GetByUserIdAndNutrientNameAsync(Guid userId, string nutrientName)
        {
            return await _dbSet
                .Include(d => d.DietRecord)
                .Where(d => d.DietRecord.UserId == userId && d.NutrientName.Contains(nutrientName))
                .OrderByDescending(d => d.DietRecord.Date)
                .ThenBy(d => d.DietRecord.MealTime)
                .ToListAsync();
        }
    }

    public class RecipeRepository : Repository<Recipe>, IRecipeRepository
    {
        public RecipeRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<Recipe>> GetByCategoryAsync(string category)
        {
            return await _dbSet
                .Where(r => r.Category == category)
                .OrderBy(r => r.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<Recipe>> GetByDifficultyAsync(string difficulty)
        {
            return await _dbSet
                .Where(r => r.Difficulty == difficulty)
                .OrderBy(r => r.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<Recipe>> SearchByNameAsync(string keyword)
        {
            return await _dbSet
                .Where(r => r.Name.Contains(keyword))
                .OrderBy(r => r.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<Recipe>> GetByIngredientsAsync(IEnumerable<string> ingredients)
        {
            var ingredientList = ingredients.ToList();
            if (!ingredientList.Any())
                return new List<Recipe>();

            return await _dbSet
                .Include(r => r.RecipeIngredients)
                .Where(r => r.RecipeIngredients.Any(ri => ingredientList.Contains(ri.IngredientName)))
                .OrderBy(r => r.Name)
                .ToListAsync();
        }
    }

    public class RecipeIngredientRepository : Repository<RecipeIngredient>, IRecipeIngredientRepository
    {
        public RecipeIngredientRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<RecipeIngredient>> GetByRecipeIdAsync(Guid recipeId)
        {
            return await _dbSet
                .Where(r => r.RecipeId == recipeId)
                .OrderBy(r => r.Order)
                .ToListAsync();
        }

        public async Task<IEnumerable<RecipeIngredient>> GetByIngredientNameAsync(string ingredientName)
        {
            return await _dbSet
                .Where(r => r.IngredientName.Contains(ingredientName))
                .OrderBy(r => r.IngredientName)
                .ToListAsync();
        }
    }

    public class RecipeStepRepository : Repository<RecipeStep>, IRecipeStepRepository
    {
        public RecipeStepRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<RecipeStep>> GetByRecipeIdAsync(Guid recipeId)
        {
            return await _dbSet
                .Where(r => r.RecipeId == recipeId)
                .OrderBy(r => r.StepNumber)
                .ToListAsync();
        }

        public async Task<IEnumerable<RecipeStep>> GetByRecipeIdOrderByStepNumberAsync(Guid recipeId)
        {
            return await _dbSet
                .Where(r => r.RecipeId == recipeId)
                .OrderBy(r => r.StepNumber)
                .ToListAsync();
        }
    }

    public class RecipeNutrientRepository : Repository<RecipeNutrient>, IRecipeNutrientRepository
    {
        public RecipeNutrientRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<RecipeNutrient>> GetByRecipeIdAsync(Guid recipeId)
        {
            return await _dbSet
                .Where(r => r.RecipeId == recipeId)
                .ToListAsync();
        }

        public async Task<IEnumerable<RecipeNutrient>> GetByNutrientNameAsync(string nutrientName)
        {
            return await _dbSet
                .Where(r => r.NutrientName.Contains(nutrientName))
                .OrderBy(r => r.NutrientName)
                .ToListAsync();
        }
    }

    public class UserRecipeRepository : Repository<UserRecipe>, IUserRecipeRepository
    {
        public UserRecipeRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<UserRecipe>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(u => u.UserId == userId)
                .OrderByDescending(u => u.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<UserRecipe>> GetByRecipeIdAsync(Guid recipeId)
        {
            return await _dbSet
                .Where(u => u.RecipeId == recipeId)
                .OrderByDescending(u => u.CreatedTime)
                .ToListAsync();
        }

        public async Task<bool> IsUserRecipeExistsAsync(Guid userId, Guid recipeId)
        {
            return await _dbSet
                .AnyAsync(u => u.UserId == userId && u.RecipeId == recipeId);
        }
    }
}